/*-----------------------------------------------------------------------------
 * @file   hal_adc.c
 * @brief  interface for ADC module operations
 * @author WLH<wanglehui8357@163.com>
 ----------------------------------------------------------------------------*/
#include "hal_adc.h"
#include "board.h"

/*-----------------------------------------------------------------------------
 * marcro define
-----------------------------------------------------------------------------*/
#define ADC_TEMP_CALIBRATION_VALUE REG16(0x1FFFF7F8)

/*-----------------------------------------------------------------------------
 * local variable
-----------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
 * local funtions
-----------------------------------------------------------------------------*/
/**
 * @brief      configure the ADC peripheral
 * @param[in]  none
 * @param[out] none
 * @retval     none
*/
static void adc_config(void)
{
    /* ADC channel length config */
    adc_channel_length_config(ADC_INSERTED_CHANNEL, 2);

    /* ADC temperature sensor channel config */
    adc_inserted_channel_config(0U, ADC_CHANNEL_16, ADC_SAMPLETIME_239POINT5);
    /* ADC internal reference voltage channel config */
    adc_inserted_channel_config(1U, ADC_CHANNEL_17, ADC_SAMPLETIME_239POINT5);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC_INSERTED_CHANNEL, ADC_EXTTRIG_INSERTED_NONE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* ADC SCAN function enable */
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    /* ADC temperature and Vrefint enable */
    adc_channel_16_to_19(ADC_TEMP_CHANNEL_SWITCH, ENABLE);
    adc_channel_16_to_19(ADC_INTERNAL_CHANNEL_SWITCH, ENABLE);

    adc_external_trigger_config(ADC_INSERTED_CHANNEL, ENABLE);

    /* 64 times sample, 6 bits shift */
    adc_oversample_mode_config(ADC_OVERSAMPLING_ALL_CONVERT, ADC_OVERSAMPLING_SHIFT_8B, ADC_OVERSAMPLING_RATIO_MUL256);
    adc_oversample_mode_enable();

    /* enable ADC interface */
    adc_enable();
    delay_1ms(1U);

    /* ADC calibration and reset calibration */
    adc_calibration_enable();
}

/*-----------------------------------------------------------------------------
 * public functions
-----------------------------------------------------------------------------*/
bool hal_adc_init(void)
{
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);
    /* config ADC clock */
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV16);

    adc_config();
    return false;
}

FP32 hal_adc_read(const U8 ch)
{
    UNUSED(ch);
    return 0;
}

FP32 hal_adc_chip_temp(void)
{
    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC_INSERTED_CHANNEL);
    /* delay a time in milliseconds */
    delay_1ms(2000U);

    /* value convert */
    int32_t value = (int32_t)ADC_TEMP_CALIBRATION_VALUE;
    FP32 temperature = ((FP32)((int32_t)ADC_IDATA0 - value) * 3.3f / 4095 * 1000 / 3.2f) + 30;
    FP32 vref_value = (ADC_IDATA1 * 3.3f / 4095);

    /* value print */
    trace_info(" the Temperature data is %2.0f degrees Celsius\r\n", temperature);
    trace_info(" the Reference voltage data is %5.3fV \r\n", vref_value);
    return temperature;
}

U8 hal_adc_ch_count(void)
{
    return 0;
}

/*------------------------------------------------------------------------------
 * STM32 HAL LIB Weak funtions override
------------------------------------------------------------------------------*/
